﻿using Kugar.Core.Exceptions;
using Kugar.Core.ExtMethod;
using Kugar.Core.Web;
using Kugar.Web.Wechat.Entities;
using Kugar.Web.Wechat.Enums;
using Kugar.Web.Wechat.MP;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Senparc.Weixin.MP;
using Senparc.Weixin.MP.AdvancedAPIs;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Kugar.Core.Log;
using Kugar.Web.WechatMP;
using Microsoft.AspNetCore.Http.Extensions;
using Newtonsoft.Json.Bson;

namespace Kugar.Web.Wechat
{

    /// <summary>
    /// 设置指定Controller或者Action调用微信公众号授权功能
    /// </summary>
    [Obsolete]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class WechatMPOAuthAttribute : Attribute , IAsyncAuthorizationFilter, IActionFilter,IAsyncActionFilter
    {
        //private Type _handler = null;
        private IMPOAuthHandler _handler = null;
        //private string _typeName = "";
        //private string _assembly = "";
        //private OAuthScope _scope = OAuthScope.snsapi_base;
        //private string _callbackUrl;

        /// <summary>
        /// 初始化特性
        /// </summary>
        /// <param name="handlerType">设置用于处理授权的类,必须实现IMPOAuthHandler接口</param>
        /// <param name="scope">授权范围,默认为base</param>
        /// <param name="callbackUrl">回调的地址,如需更改,请检查对应的路由是否配置完成,回调的是MPOAuthCallbackController的Callback函数</param>
        public WechatMPOAuthAttribute(Type handlerType, WechatOAuthScope scope = WechatOAuthScope.snsapi_base,
            string callbackUrl = "/Core/MPCallback/Callback")
        {
            Scope = scope;

            //_handler = handlerType ?? throw new ArgumentNullException(nameof(handlerType));

            if (handlerType != null)
            {
                HandleTypeName = handlerType.Namespace + "." + handlerType.Name;
                AssemblyName = handlerType.Assembly.FullName;
                _handler = MPOAuthHanderInfoCache
                    .GetMPHandler(HandleTypeName); // ( IMPOAuthHandler)handlerType.CreateInstance();
            }

            if (string.IsNullOrEmpty(callbackUrl))
            {
                throw new ArgumentOutOfRangeException(nameof(callbackUrl));
            }

            CallbackUrl = callbackUrl;
        }

        /// <summary>
        /// 一般是在action上使用,处理类使用controller中定义的,本构造函数必须是在controller已标注了处理类之后,才能在action中使用
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="callbackUrl"></param>
        public WechatMPOAuthAttribute(WechatOAuthScope scope = WechatOAuthScope.snsapi_base,
            string callbackUrl = "/Core/MPCallback/Callback") : this(null, scope, callbackUrl)
        {
        }

        public string HandleTypeName { set; get; }

        public string CallbackUrl { set; get; }

        public string AssemblyName { set; get; }

        public WechatOAuthScope Scope { set; get; }


        //public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        //{
        //    var controller = (Controller)context.Controller;

        //    LoggerManager.Default.Debug("5");

        //    var handler = _handler;

        //    if (handler == null)
        //    {
        //        var handlerName = HandleTypeName;

        //        if (string.IsNullOrEmpty(handlerName))
        //        {
        //            HandleTypeName = MPOAuthHanderInfoCache
        //                .GetMemberHandlerInfo((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo)
        //                ?.HanderTypeName;
        //        }

        //        handler = MPOAuthHanderInfoCache.GetMPHandler(handlerName);
        //    }

        //    // ?? MPOAuthHanderInfoCache.GetMPHandler(HandleTypeName.IfEmptyOrWhileSpace(x=> MPOAuthHanderInfoCache.GetMemberHandlerInfo(context.ActionDescriptor.)));

        //    var wxUserJsonStr = context.HttpContext.Session.GetString("WechatMPUser");

        //    LoggerManager.Default.Debug("6");

        //    if (wxUserJsonStr == null)
        //    {
        //        throw new ArgumentNullException("微信授权用户信息获取出错,无法从session获取用户信息,请检查session配置");
        //    }

        //    var appID = context.HttpContext.Items["AppID"].ToStringEx();

        //    var wxUser = JsonConvert.DeserializeObject<WechatUserOAuth>(wxUserJsonStr);

        //    if (controller is IWechatMPOAuthController c1)
        //    {
        //        c1.CurrentMPUser = wxUser;
        //    }

        //    controller.HttpContext.User
        //        .AddClaim("OpenID", wxUser.OpenID)
        //        .AddClaim("WechatMPUser", JsonConvert.SerializeObject(wxUser));

        //    await handler.OnUserAuthorityAsync(appID, wxUser, controller);

        //    await next();
        //}

        //public void OnActionExecuting(ActionExecutingContext context)
        //{
        //    var controller = (Controller)context.Controller;

        //    LoggerManager.Default.Debug("5");

        //    var handler = _handler;

        //    if (handler == null)
        //    {
        //        var handlerName = HandleTypeName;

        //        if (string.IsNullOrEmpty(handlerName))
        //        {
        //            HandleTypeName = MPOAuthHanderInfoCache
        //                .GetMemberHandlerInfo((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo)
        //                ?.HanderTypeName;
        //        }

        //        handler = MPOAuthHanderInfoCache.GetMPHandler(handlerName);
        //    }

        //    // ?? MPOAuthHanderInfoCache.GetMPHandler(HandleTypeName.IfEmptyOrWhileSpace(x=> MPOAuthHanderInfoCache.GetMemberHandlerInfo(context.ActionDescriptor.)));

        //    var wxUserJsonStr = context.HttpContext.Session.GetString("WechatMPUser");

        //    LoggerManager.Default.Debug("6");

        //    if (wxUserJsonStr == null)
        //    {
        //        throw new ArgumentNullException("微信授权用户信息获取出错,无法从session获取用户信息,请检查session配置");
        //    }

        //    var appID = context.HttpContext.Items["AppID"].ToStringEx();

        //    var wxUser = JsonConvert.DeserializeObject<WechatUserOAuth>(wxUserJsonStr);

        //    if (controller is IWechatMPOAuthController c1)
        //    {
        //        c1.CurrentMPUser = wxUser;
        //    }

        //    controller.HttpContext.User
        //        .AddClaim("OpenID", wxUser.OpenID)
        //        .AddClaim("WechatMPUser", JsonConvert.SerializeObject(wxUser));

        //    handler.OnUserAuthorityAsync(appID, wxUser, controller).Wait();
        //}

        //public void OnActionExecuted(ActionExecutedContext context)
        //{
        //    //throw new NotImplementedException();
        //}
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var wxUserJsonStr = "";
            WechatUserOAuth user = null;

            var descriptor = context.ActionDescriptor as ControllerActionDescriptor;

            //if (context.HttpContext.Request.Cookies.TryGetValue("muk", out var cookie))
            //{
            //    //LoggerManager.Default.Debug("cookie:" + cookie);

            //}

            var handler =
                (IMPOAuthWithSchemeHandler) context.HttpContext.RequestServices.GetService(
                    typeof(IMPOAuthWithSchemeHandler));

            var mp = handler.MPGetter(context.HttpContext, context.ActionDescriptor);

            if (await _handler.CheckAuthority(context))
            {
                if (context.HttpContext.Session.TryGetValue("WechatMPUser", out var tmp1))
                {
                    wxUserJsonStr = Encoding.UTF8.GetString(tmp1);

                    if (!string.IsNullOrWhiteSpace(wxUserJsonStr))
                    {
                        user = JsonConvert.DeserializeObject<WechatUserOAuth>(wxUserJsonStr);

                        context.HttpContext.User
                            .AddClaim("OpenID", user.OpenID)
                            .AddClaim("WechatMPUser", JsonConvert.SerializeObject(user));
                        
                    }
                }
            }

            if (user != null && user.Scope >= Scope)
            {
                context.HttpContext.Items["AppID"] = mp.appID;
                context.HttpContext.Items["WechatMPUser"] = user;
            }
            else
            {
                if (!descriptor.MethodInfo.GetCustomAttributes(typeof(SkipWechatMPAuthorityAttribute), true).Any())
                {
                    //var mp = handler.MPGetter(filterContext, filterContext.ActionDescriptor);

                    var appID = mp.appID;
                    var appserect = mp.appSerect;

                    var json = new JObject()
                    {
                        ["BackUrl"] = context.HttpContext.Request.GetDisplayUrl(),
                        ["Scope"] = (int)Scope,
                        ["AppID"] = appID,
                        ["AppSecret"] = appserect,

                    };

                    var guid = HttpUtility.UrlEncode(Guid.NewGuid().ToStringEx());

                    context.HttpContext.Session.SetString(guid, json.ToStringEx());
                    context.HttpContext.Session.SetString($"{guid}_handler", HandleTypeName);
                    //filterContext.HttpContext.Session.SetString($"{guid}_assembly", handlerInfo.AssemblyName) ;

                    var callbackUrl =  CallbackUrl;

                    if (!callbackUrl.StartsWith("http", StringComparison.CurrentCultureIgnoreCase))
                    {
                        var host = context.HttpContext.Request.Host;

                        if (callbackUrl[0] == '/')
                        {
                            callbackUrl =
                                $"http://{host.Host}{CallbackUrl}";
                        }
                        else
                        {
                            callbackUrl =
                                $"http://{host.Host}/{CallbackUrl}";
                        }
                    }

                    var url = OAuthApi.GetAuthorizeUrl(appID, callbackUrl, guid, (OAuthScope)(int)Scope,
                        "code");

                    LoggerManager.Default.Debug("跳转到:" + url);

                    context.HttpContext.Session.SetString($"{guid}_handler",  HandleTypeName);
                    
                    context.Result = new RedirectResult(url);
                }
                
            }
            
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            var controller = (Controller) context.Controller;

            var user = (WechatUserOAuth) context.HttpContext.Items["WechatMPUser"];

            var appID = context.HttpContext.Items["AppID"].ToStringEx();


            if (controller is IWechatMPOAuthController c1)
            {
                c1.CurrentMPUser = user;
                c1.AppID = appID;
            }

            _handler.OnUserAuthorityAsync(appID, user, controller).Wait();
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            
        }

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var controller = (Controller)context.Controller;

            var user = (WechatUserOAuth)context.HttpContext.Items["WechatMPUser"];

            var appID = context.HttpContext.Items["AppID"].ToStringEx();

            if (controller is IWechatMPOAuthController c1)
            {
                c1.CurrentMPUser = user;
                c1.AppID = appID;
            }

            await _handler.OnUserAuthorityAsync(appID, user, controller);

            await next();
        }
    }

    //public class WechatMPOAuthRequirement : IAuthorizationRequirement
    //{
    //    //Add any custom requirement properties if you have them
    //    public WechatMPOAuthRequirement()
    //    {
    //    }
    //}

    //public class WechatMPOAuthPolicyHandler : AttributeAuthorizationHandler<WechatMPOAuthRequirement, WechatMPOAuthAttribute>
    //{
    //    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
    //        AuthorizationFilterContext filterContext, WechatMPOAuthRequirement requirement,
    //        IEnumerable<WechatMPOAuthAttribute> attributes)
    //    {
    //        var attr = attributes.FirstOrDefault();

    //        CalcedActionOAuthHandlerInfo handlerInfo = null;

    //        var descriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;

    //        if (descriptor != null)
    //        {
    //            handlerInfo = MPOAuthHanderInfoCache.GetMemberHandlerInfo(descriptor.MethodInfo);
    //        }

    //        if (handlerInfo == null)
    //        {
    //            throw new ArgumentOutOfRangeException();
    //        }

    //        var handler =
    //            MPOAuthHanderInfoCache.GetMPHandler(handlerInfo
    //                .HanderTypeName); // ( IMPOAuthHandler)handlerType.CreateInstance();

    //        var wxUserJsonStr = "";
    //        WechatUserOAuth user = null;

            
    //        if (filterContext.HttpContext.Request.Cookies.TryGetValue("muk", out var cookie))
    //        {
    //            LoggerManager.Default.Debug("cookie:" + cookie);
                
    //        }

    //        var mp = handler.MPGetter(filterContext, filterContext.ActionDescriptor);

    //        if (handler.CheckAuthority(filterContext))
    //        {
    //            if (filterContext.HttpContext.Session.TryGetValue("WechatMPUser", out var tmp1))
    //            {
    //                wxUserJsonStr = Encoding.UTF8.GetString(tmp1);

    //                if (!string.IsNullOrWhiteSpace(wxUserJsonStr))
    //                {
    //                    user = JsonConvert.DeserializeObject<WechatUserOAuth>(wxUserJsonStr);

    //                    filterContext.HttpContext.User
    //                        .AddClaim("OpenID", user.OpenID)
    //                        .AddClaim("WechatMPUser", JsonConvert.SerializeObject(user));

    //                    //handler.OnUserAuthorityAsync(mp.appID, user, filterContext).Wait();
    //                }
    //            }
    //        }

    //        if (user != null  && user.Scope >= handlerInfo.Scope)
    //        {
    //            filterContext.HttpContext.Items["AppID"] = mp.appID;

    //            context.Succeed(requirement);
    //        }
    //        else
    //        {
    //            if (!descriptor.MethodInfo.GetCustomAttributes(typeof(SkipWechatMPAuthorityAttribute), true).Any())
    //            {
    //                //var mp = handler.MPGetter(filterContext, filterContext.ActionDescriptor);

    //                var appID = mp.appID;
    //                var appserect = mp.appSerect;

    //                var json = new JObject()
    //                           {
    //                               ["BackUrl"] = filterContext.HttpContext.Request.GetDisplayUrl(),
    //                               ["Scope"] = (int) handlerInfo.Scope,
    //                               ["AppID"] = appID,
    //                               ["AppSerect"] = appserect,
                                  
    //                           };

    //                var guid =HttpUtility.UrlEncode(Guid.NewGuid().ToStringEx());

    //                filterContext.HttpContext.Session.SetString(guid, json.ToStringEx());
    //                filterContext.HttpContext.Session.SetString($"{guid}_handler", handlerInfo.HanderTypeName);
    //                //filterContext.HttpContext.Session.SetString($"{guid}_assembly", handlerInfo.AssemblyName) ;

    //                var callbackUrl = handlerInfo.CallbackUrl;

    //                if (!callbackUrl.StartsWith("http", StringComparison.CurrentCultureIgnoreCase))
    //                {
    //                    var host = filterContext.HttpContext.Request.Host;

    //                    if (callbackUrl[0] == '/')
    //                    {
    //                        callbackUrl =
    //                            $"http://{host.Host}{handlerInfo.CallbackUrl}";
    //                    }
    //                    else
    //                    {
    //                        callbackUrl =
    //                            $"http://{host.Host}/{handlerInfo.CallbackUrl}";
    //                    }
    //                }

    //                var url = OAuthApi.GetAuthorizeUrl(appID, callbackUrl, guid, (OAuthScope) (int) handlerInfo.Scope,
    //                    "code");

    //                LoggerManager.Default.Debug("跳转到:" + url);

    //                filterContext.HttpContext.Session.SetString($"{guid}_handler", attr.HandleTypeName);


    //                filterContext.Result = new RedirectResult(url);
    //            }

    //            context.Succeed(requirement);
    //        }

    //        return Task.CompletedTask;
    //    }
    //}

    /// <summary>
    /// 跳过微信授权检查
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class SkipWechatMPAuthorityAttribute : Attribute
    {
    }
}